class_name Area2DDetector
extends Resource

@export var detector_id:int
@export var detector_desc:String
@export var timing:GameEnum.Area2DDetectorTiming
@export var detect_range:GameEnum.Area2DDetectorDetectRange
@export var area_idxs:Array[int] = []
@export var is_repeat_detect:bool
@export var record_duration:float
@export var active:bool = false
var detect_target_dict:Dictionary = {}
var callback_dict:Dictionary = {}
var areas:Array[Area2D] = []
var area2DDetectComponent:Area2DDetectComponent
signal on_detect_target(entity)

func init_detector(component:Area2DDetectComponent):
	area2DDetectComponent = component
	areas = []
	for idx in area_idxs:
		areas.append(area2DDetectComponent.get_area2d(idx))
func set_active(is_active:bool):
	active = is_active
func set_area2d_active(is_active:bool):
	for area2d:Area2D in areas:
		area2d.monitoring = is_active
		area2d.monitorable = is_active
func set_layer_mask(mask:int):
	for area2d:Area2D in areas:
		area2d.collision_mask = mask 
func check_repeat_detect(target,is_enter:bool):
	var entity = Util.get_entity_in_parent(target)
	if not entity or not active:
		return
	if is_repeat_detect or timing == GameEnum.Area2DDetectorTiming.Stay:
		if is_enter:
			detect_target_dict[entity] = Time.get_ticks_msec()
		else:
			detect_target_dict.erase(entity)
		on_detect_target.emit(entity)
	elif is_repeat_detect == false and (detect_target_dict.has(entity) == false or (record_duration > 0 and detect_target_dict[entity] + record_duration * 1000 > Time.get_ticks_msec())):
		detect_target_dict[entity] = Time.get_ticks_msec()
		on_detect_target.emit(entity)
func detect_update():
	if timing != GameEnum.Area2DDetectorTiming.Stay:
		return
	for entity in detect_target_dict.keys():
		on_detect_target.emit(entity)
func set_on_detect_target(callback:Callable,is_connect:bool):
	var callback_temp
	if is_connect:
		callback_temp = func (target):
			if active:
				callback.call(target)
		callback_dict[callback.hash()] = callback_temp
	else:
		if callback_dict.has(callback.hash()):
			callback_temp = callback_dict[callback.hash()]
			callback_dict.erase(callback.hash())
	if is_connect and not on_detect_target.is_connected(callback_temp):
		on_detect_target.connect(callback_temp)
	elif not is_connect and on_detect_target.is_connected(callback_temp):
		on_detect_target.disconnect(callback_temp)
		
	for area2d:Area2D in areas:
		if is_connect:
			if detect_range == GameEnum.Area2DDetectorDetectRange.Area or detect_range == GameEnum.Area2DDetectorDetectRange.AB:
				if timing == GameEnum.Area2DDetectorTiming.Enter and not area2d.area_entered.is_connected(check_repeat_detect):
					area2d.area_entered.connect(check_repeat_detect.bind(true))
				if timing == GameEnum.Area2DDetectorTiming.Exit and not area2d.area_exited.is_connected(check_repeat_detect):
					area2d.area_exited.connect(check_repeat_detect.bind(false))
				if timing == GameEnum.Area2DDetectorTiming.Stay and not area2d.area_entered.is_connected(check_repeat_detect) and not area2d.area_exited.is_connected(check_repeat_detect):
					area2d.area_entered.connect(check_repeat_detect.bind(true))
					area2d.area_exited.connect(check_repeat_detect.bind(false))
			if detect_range == GameEnum.Area2DDetectorDetectRange.Body or detect_range == GameEnum.Area2DDetectorDetectRange.AB:
				if timing == GameEnum.Area2DDetectorTiming.Enter and not area2d.body_entered.is_connected(check_repeat_detect):
					area2d.body_entered.connect(check_repeat_detect.bind(true))
				if timing == GameEnum.Area2DDetectorTiming.Exit and not area2d.body_exited.is_connected(check_repeat_detect):
					area2d.body_exited.connect(check_repeat_detect.bind(false))
				if timing == GameEnum.Area2DDetectorTiming.Stay and not area2d.body_entered.is_connected(check_repeat_detect) and not area2d.body_exited.is_connected(check_repeat_detect):
					area2d.body_entered.connect(check_repeat_detect.bind(true))
					area2d.body_exited.connect(check_repeat_detect.bind(false))
		else:
			if detect_range == GameEnum.Area2DDetectorDetectRange.Area or detect_range == GameEnum.Area2DDetectorDetectRange.AB:
				if timing == GameEnum.Area2DDetectorTiming.Enter and area2d.area_entered.is_connected(check_repeat_detect):
					area2d.area_entered.disconnect(check_repeat_detect.bind(true))
				if timing == GameEnum.Area2DDetectorTiming.Exit and area2d.area_exited.is_connected(check_repeat_detect):
					area2d.area_exited.disconnect(check_repeat_detect.bind(false))
				if timing == GameEnum.Area2DDetectorTiming.Stay and area2d.area_entered.is_connected(check_repeat_detect) and area2d.area_exited.is_connected(check_repeat_detect):
					area2d.area_entered.disconnect(check_repeat_detect.bind(true))
					area2d.area_exited.disconnect(check_repeat_detect.bind(false))
			if detect_range == GameEnum.Area2DDetectorDetectRange.Body or detect_range == GameEnum.Area2DDetectorDetectRange.AB:
				if timing == GameEnum.Area2DDetectorTiming.Enter and area2d.body_entered.is_connected(check_repeat_detect):
					area2d.body_entered.disconnect(check_repeat_detect.bind(true))
				if timing == GameEnum.Area2DDetectorTiming.Exit and area2d.body_exited.is_connected(check_repeat_detect):
					area2d.body_exited.disconnect(check_repeat_detect.bind(false))
				if timing == GameEnum.Area2DDetectorTiming.Stay and area2d.body_entered.is_connected(check_repeat_detect) and area2d.body_exited.is_connected(check_repeat_detect):
					area2d.body_entered.disconnect(check_repeat_detect.bind(true))
					area2d.body_exited.disconnect(check_repeat_detect.bind(false))
func clear_detect_target_dict():
	if detect_target_dict == null:
		return
	detect_target_dict.clear()
func check_entity_is_detecting(entity):
	return detect_target_dict.get(entity) != null
